<template>
  <el-card class="container">
    <!-- 头部 -->
    <template #header>
      <div class="card-header">
        <span>文章管理</span>"
        <el-button type="primary" :icon="Plus" @click="addArticle">添加文章</el-button>
      </div>
    </template>
    <!-- 搜索表单 -->
    <el-form :inline="true" class="demo-form-inline">
      <el-form-item label="文章分类:">
        <el-select placeholder="请选择" clearable style="width: 240px;" v-model="categoryId">
          <el-option label="全部"></el-option>
          <el-option v-for="c in categoryListData" :key="c.id" :label="c.categoryName" :value="c.id"></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="发布状态">
        <el-select placeholder="请选择" clearable style="width: 200px;" v-model="state">
          <!-- 不写value，则选“全部”state收集到的是false,如果啥都不选，则收集的是undefined -->
          <el-option label="全部" />
          <el-option label="草稿" value="草稿" />
          <el-option label="已发布" value="已发布" />
        </el-select>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" :icon="Search" @click="search">搜索</el-button>
      </el-form-item>
      <el-form-item>
        <el-button @click="reSet">重置</el-button>
      </el-form-item>
    </el-form>
    <!-- 数据表格 -->
    <el-table :data="articleListData" :border="true" style="width: 100%">
      <el-table-column type="index" label="序号" width="60" align="center" />
      <el-table-column prop="title" label="文章标题" width="350">
        <template #default="{ row }">
          <el-button link type="primary" @click="titleDialog(row)">{{ row.title }}</el-button>
        </template>
      </el-table-column>
      <el-table-column prop="categoryName" label="分类" width="100" align="center" />
      <!-- TODO:时间格式待优化 -->
      <el-table-column prop="createTime" label="发表时间" />
      <el-table-column prop="state" label="状态" />
      <el-table-column label="操作" width="150">
        <template #default="{ row }">
          <el-button type="primary" size="small" :icon="Edit" @click="editArticle(row)" />
          <el-button type="danger" size="small" :icon="Delete" @click="deleteArticle(row)" />
        </template>
      </el-table-column>
    </el-table>
    <!-- 点文章标题后出现的弹窗 -->
    <el-dialog v-model="titleVisible" :title="my.title" width="400" align="center">
      <div class="title-image">
        <div style="text-align: center;color:#008c8c;font-size: 18px;font-weight: 700;margin-bottom: 10px;">文章封面：</div>
        <img :src="my.coverImg" alt="" style="width: 100%;">
      </div>
      <div class="title-content" style="margin-top:20px;">
        <span style="color: #008c8c;font-size: 18px;font-weight: 700;">文章内容：</span>
        <p>{{ my.content }}</p>
      </div>
      <template #footer>
        <el-button type="primary" @click="titleVisible = false">确认</el-button>
      </template>
    </el-dialog>
    <!-- 分页器 -->
    <el-pagination class="footer-panination" v-model:current-page="pageNum" v-model:page-size="pageSize"
      :page-sizes="[3, 5, 10, 15]" size="default" :disabled="disabled" :background="background"
      layout=" prev, pager, next, sizes, jumper, total" :total="total" @size-change="handleSizeChange"
      @current-change="handleCurrentChange" />

    <!-- 抽屉 -->
    <el-drawer v-model="drawerVisible" title="添加文章" :before-close="handleClose" direction="rtl" size="50%">
      <div class="demo-drawer__content">
        <el-form :model="articleForm" :rules="rules" ref="articleRef">
          <el-form-item label="文章标题" prop="title" :label-width="formLabelWidth">
            <el-input autocomplete="off" placeholder="请输入标题" v-model="articleForm.title" />
          </el-form-item>
          <el-form-item label="文章分类" prop="categoryId">
            <el-select placeholder="请选择" v-model="articleForm.categoryId" clearable style="width: 120px;">
              <el-option v-for="c in categoryListData" :label="c.categoryName" :value="c.id" />
            </el-select>
          </el-form-item>
          <el-form-item label="文章封面" prop="coverImg">
            <!-- TODO:删除照片时样式闪退问题+上传图片校验问题【待解决】 -->
            <!-- 上传 -->
            <!-- <el-upload class="avatar-uploader" action="/api/upload" :limit="1" list-type="picture-card"
              :headers="{ Authorization: GET_TOKEN() }" :auto-upload="true" :on-success="handleAvatarSuccess"
              :before-upload="beforeAvatarUpload">
              <img v-if="imageUrl" :src="imageUrl" class="avatar" />
              <el-icon v-else class="avatar-uploader-icon">
                <Plus />
              </el-icon>
            </el-upload> -->
            <el-upload class="avatar-uploader" action="/api/upload" :headers="{ 'Authorization': GET_TOKEN() }"
              list-type="picture-card" :auto-upload="true" :limit="1" :on-preview="handlePictureCardPreview"
              :on-remove="handleRemove" :before-upload="beforeAvatarUpload" :on-success="successUpload">
              <img v-if="articleForm.coverImg" :src="articleForm.coverImg" class="upload-image" alt="文章封面">
              <el-icon v-else>
                <Plus />
              </el-icon>
              <!-- <div v-if="articleForm.coverImg" @click.stop="dialogVisible = !dialogVisible">
                <img :src="articleModel.coverImg" class="avatar" />
                <span class="el-img-icon" v-if="isEndUpload">
                  <el-icon size="large"><zoom-in /></el-icon>
                </span>
              </div>
              <el-icon v-else class="avatar-uploader-icon">
                <Plus />
              </el-icon> -->
            </el-upload>
            <!-- 新增错误提示 -->
            <!-- <div v-if="uploadError" class="upload-error-tip">{{ uploadError }}</div> -->
            <!-- 封面预览弹窗 -->
            <el-dialog v-model="preImgVisible" width="600" align-center>
              <img class="dialogImage" :src="coverImg" alt="文章封面" />
            </el-dialog>
          </el-form-item>
          <!-- 富文本编辑器 -->
          <el-form-item label="文章内容" prop="content">
            <div class="editor">
              <quill-editor theme="snow" v-model:content="articleForm.content" contentType="html"
                ref="quill"></quill-editor>
            </div>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="addOrUpdateArticle('已发布')">发布</el-button>
            <el-button @click="addOrUpdateArticle('草稿')">草稿</el-button>
          </el-form-item>
        </el-form>
      </div>
    </el-drawer>

  </el-card>
</template>

<script setup>
import { articleAddApi, articleDeleteApi, articleListApi, articleUpdateApi } from '@/api/article';
import { categoryListApi } from '@/api/category';
import { GET_TOKEN } from '@/utils/token';
import { Delete, Edit, Plus, Search } from '@element-plus/icons-vue';
import { onMounted, reactive, ref } from 'vue';
// 引入富文本编辑器相关
import { QuillEditor } from "@vueup/vue-quill";
import "@vueup/vue-quill/dist/vue-quill.snow.css";
import { ElMessage } from 'element-plus';

// 分页器
const total = ref()//总条数
const pageSize = ref(3)//每页展示的条数
const pageNum = ref(1)//当前页码
// 搜索表单
const categoryId = ref()//分类ID
const state = ref()//文章状态

// 控制抽屉的显示与隐藏
const drawerVisible = ref(false)
const coverImg = ref('')//封面图片地址
// 控制图片预览的大图是否显示
const preImgVisible = ref(false)
// const disabled = ref(false)
// 控制标题弹窗的显示
const titleVisible = ref(false)

const my = reactive({
  title: '',
  coverImg: '',
  content: ''
})
const titleDialog = (row) => {
  console.log('row:', row)
  titleVisible.value = true
  my.title = row.title
  my.content = row.content
  my.coverImg = row.coverImg
  console.log('my:', my)
}

// 分类列表
const categoryListData = ref()
const getCategoryList = async () => {
  let res = await categoryListApi()
  categoryListData.value = res.data
}
// 文章信息
const articleForm = reactive({
  id: '',
  title: '',
  categoryId: '',
  coverImg: '',
  content: '',
  state: ''
})
const articleRef = ref()
// 表单校验
const rules = {
  title: [
    { required: true, message: '请输入文章标题', trigger: 'blur' }
  ],
  categoryId: [
    { required: true, message: '请选择文章分类', trigger: 'blur' }
  ],
  coverImg: [
    { required: true, message: '请上传封面图片', trigger: 'blur' }
  ],
  // content: [
  //   { required: true, message: '请输入文章内容', trigger: 'blur' }
  // ]
  content: [
    {
      validator: (rule, value, callback) => {
        if (!value || value === '<p><br></p>' || value === '<p></p>') {
          callback(new Error('请输入文章内容'))
        } else {
          callback()
        }
      },
      trigger: 'blur'
    }
  ]
}
// 通过watch监听回显
// const quill = ref();
// watch(
//   drawerVisible,
//   () => {
//     if (!articleForm.id && quill.value !== undefined) quill.value.setHTML("");
//   },
//   { deep: true }
// );
// 文章列表
const articleListData = ref()
const getArticleList = async () => {
  let params = {
    pageNum: pageNum.value,
    pageSize: pageSize.value,
    categoryId: categoryId.value ? categoryId.value : null,
    state: state.value ? state.value : null
  }
  let res = await articleListApi(params)
  total.value = res.data.total
  articleListData.value = res.data.items
  // TODO:性能待优化
  // 处理数据，给数据模型扩展一个属性categoryName【分类名称】
  for (let i = 0; i < articleListData.value.length; i++) {
    let article = articleListData.value[i]
    for (let j = 0; j < categoryListData.value.length; j++) {
      if (article.categoryId === categoryListData.value[j].id) {
        article.categoryName = categoryListData.value[j].categoryName
      }
    }
  }
}

onMounted(() => {
  getCategoryList()
  getArticleList()
})

// 当每页展示条数发生变化
const handleSizeChange = () => {
  getArticleList()
}
// 当当前页码发现变化的时候
const handleCurrentChange = () => {
  getArticleList()
}

// 重置
const reSet = () => {
  categoryId.value = ''
  state.value = ''
  // getCategoryList()这个只需在页面渲染之前执行一次应该就行了
  getArticleList()
}
// 搜索
const search = () => {
  getCategoryList()
  getArticleList()
}
// 删除
const deleteArticle = (row) => {
  ElMessageBox.confirm(
    `你确定删除${row.title}吗?`,
    'Warning',
    {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
      center: true,
    }
  )
    .then(async () => {
      await articleDeleteApi(row.id)
      // 删除成功需再次返回新数据刷新页面
      getCategoryList()
      getArticleList()
      ElMessage({
        type: 'success',
        // articleDeleteApi(row.id),
        message: '删除成功',
      })
    })
    .catch(() => {
      ElMessage({
        type: 'info',
        message: '取消删除',
      })
    })
}
// 添加
const addArticle = () => {
  drawerVisible.value = true
  clearArticleForm()
}

// 删除封面
// TODO:应该把上传到服务器的图片也删除掉
const handleRemove = (uploadFile, uploadFiles) => {
  // console.log(uploadFile, uploadFiles)
  articleForm.coverImg = ''
}
// 预览封面
const handlePictureCardPreview = (file) => {
  coverImg.value = file.url
  preImgVisible.value = true
}
// 上传文件格式限制
// const uploadError = ref()
const beforeAvatarUpload = (rawFile) => {
  if (rawFile.type !== 'image/jpeg') {
    ElMessage.error('图片格式必须是jpg格式')
    // uploadError.value = '图片格式必须是jpg格式'
    return false
  } else if (rawFile.size / 1024 / 1024 > 2) {
    ElMessage.error('图片大小不能超过2MB!')
    // uploadError.value = '图片大小不能超过2MB'
    return false
  }
  return true
}
// 文件上传成功的回调
const successUpload = (res) => {
  // console.log("upload:",res)
  articleForm.coverImg = res.data
}
// 清空文章数据
const clearArticleForm = () => {
  articleForm.id = ''
  articleForm.title = ''
  articleForm.categoryId = ''
  articleForm.coverImg = ''
  articleForm.content = ''
  articleForm.state = ''
}
// 新增文章
const addOrUpdateArticle = async (state) => {
  articleForm.state = state
  await articleRef.value.validate()
  // articleRef.value.validate((valid,fields)=>{
  //   if(valid){
  //     console.log("表单校验通过fields:",fields)
  //   }else {
  //     console.log("表单校验不通过fields:",fields)
  //   }
  // })
  // console.log("表单校验通过articleForm:", articleForm)
  // 因为富文本编辑器中的内容始终会包含一些html标签，所以需去掉html
  articleForm.content = articleForm.content.replace(/<[^>]*>/g, '')
  if (articleForm.id) {
    if (articleForm.coverImg !== originalData.coverImg) {
      // 又因为sv7o32s80.hn-bkt.clouddn.com/微信头像.jpg不是一个合法的地址【不符合后端的@URL校验规则】所以要改写
      articleForm.coverImg = 'http://' + articleForm.coverImg
    }
    // 保证至少修改了一个属性
    const keys1 = Object.keys(originalData)
    // const keys2 = Object.keys(articleForm)
    if (keys1.every(key => originalData[key] === articleForm[key])) {
      ElMessage.error('至少修改一个属性')
      // clearArticleForm()
      return
    }
    await articleUpdateApi(articleForm)
    ElMessage.success('修改文章成功')
  } else {
    // 又因为sv7o32s80.hn-bkt.clouddn.com/微信头像.jpg不是一个合法的地址【不符合后端的@URL校验规则】所以要改写
    articleForm.coverImg = 'http://' + articleForm.coverImg
    await articleAddApi(articleForm)
    ElMessage.success("添加文章成功")
  }
  // 添加成功之后还需隐藏drawer抽屉+更新数据列表+清空文章articleForm信息
  drawerVisible.value = false
  getArticleList()
  clearArticleForm()
}
// 修改文章
// TODO:应保证至少修改一个属性
const originalData = {}
const editArticle = (row) => {
  drawerVisible.value = true
  console.log("修改文章row:", row)
  Object.assign(articleForm, row)//回显数据
  Object.assign(originalData, row)//存储修改前的数据
  console.log("articleForm:", articleForm)
  console.log('originalData:', originalData)
}
</script>

<style scoped lang="scss">
.container {
  height: 100%;

  .card-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

  .footer-panination {
    margin: 20px 30px 0 0;
    float: right;
  }

  .avatar-uploader {
    display: block;

    .avatar {
      width: 178px;
      height: 178px;
      display: block;
    }

    .el-upload {
      border: 1px dashed var(--el-border-color);
      border-radius: 6px;
      cursor: pointer;
      position: relative;
      overflow: hidden;
      transition: var(--el-transition-duration-fast);

    }
  }

  .upload-error-tip {
    display: block;
    color: red;
  }

  .upload-image {
    width: 100%;
  }

  .dialogImage {
    width: 100%;
  }

  .editor {
    width: 100%;

    :deep(.ql-editor) {
      min-height: 200px;
    }
  }

}
</style>
<style scoped></style>

<style>
.avatar-uploader .avatar-uploader .el-upload:hover {
  border-color: var(--el-color-primary);
}

.el-icon.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  text-align: center;
}

/* 隐藏第二个及以上的上传按钮 */
.avatar-uploader .el-upload-list--picture-card>*:not(:first-child) {
  display: none;
}
</style>